(function(window, undefined) { var protocol = window.location.protocol; var localUreadData=[],hasNewMsg=false,hasGetData=false; var defaults = { realtime: protocol+'//s{0}-im-notify.csdn.net' , api: protocol+'//svc-notify.csdn.net' , app:'http://msg.csdn.net' , space: protocol+'//my.csdn.net/' , count: 5 , subCount: 5 , staticUrl: protocol+'//csdnimg.cn/rabbit/notev2/' , cssUrl: 'css/style.css' , 'realtime.js': 'js/realtime.js' // base staticUrl // , 'channel': 'message' , 'socket.io.js': 'js/socket.io.js' // , 'socket.io options': { transports: ["xhr-polling", "jsonp-polling"]} } // , csdn = window.csdn || (window.csdn = {}) , isShowMsg = true // && location.search === '?smsg=1' // DEV , friendlyErrors = { 'timeout': '请求超时,请检查网络后重试!' , 'abort': '请求被中止!' , 'parsererror': '解析错误,请检查网络后重试!' , 'No id supplied': '未登录或登录超时,请重新登录!' , 'locked': '' } ; var getCookie =function (objName){//获取指定名称的cookie的值 var arrStr = document.cookie.split("; "); for(var i = 0;i < arrStr.length;i ++){ var temp = arrStr[i].split("="); if(temp[0] == objName) return decodeURI(temp[1]); } } // if (Function.prototype.bind === undefined) { Function.prototype.bind = function (ctx) { var self = this; return function () { self.apply(ctx, [].slice(arguments, 0)); }; }; } function log() { if (typeof console !== 'undefined') { Function.prototype.apply.call(console.log, console, Array.prototype.slice.call(arguments)); } } var $ , currUser = { username: '' } //登录用户对象 ; csdn.note = function(conf) { $ = jQuery; //配置项 this.conf = conf; //Dom节点 this.Dom = {}; //初始化 this.init(); }; csdn.note.prototype = { /* * 【初始化入口】 */ init: function() { var self = this, opts = self.conf; opts.wrap = $('#' + opts.wrapId); if(typeof opts.count === 'string') { opts.count = parseInt(opts.count, 10) || undefined; } if(typeof opts.subCount === 'string') { opts.subCount = parseInt(opts.subCount, 10) || undefined; } self.conf = $.extend({}, defaults, // opts); //初始化消息列表 self.getDoms(); //检查用户登录 self.checkLogin(function(data) { // if(isShowMsg) { //加载样式与事件 self.loadCss(self.staticUrl(self.conf.cssUrl)); self.addEvent(); } // 初始化实时系统 self.initRealtime(); }); }, loadCss : function(src, callback){ $('').appendTo('head:first').load(function(){ callback && callback(); }).attr('href', src); }, /** * 显示指定范围的.loading元素,返回一个函数,执行后将隐藏loading * @param {String} [selector=''] css选择器,配合ctx决定使用哪个.loading * @param {jQuery Object} ctx=wrap .loading所在的上下文 * @return {Function(Function(Boolean loading) doneCallback)} * 隐藏已显示的.loading元素,并在隐藏完毕后调用doneCallback * loading参数用于指示.loading当前还在显示中(共享loading时会有这种状况) */ loading: function (selector, ctx) { var self = this , ctx = typeof selector === 'object' ? selector : self.Dom.wrap , selector = typeof selector === 'string' ? selector : '' , el = $(selector + ' .loading', ctx) , num = (el.data('loadingCount') || 0) + 1 , completed = false ; el.show().data('loadingCount', num); return function (callback) { if(completed) return; num = el.data('loadingCount') - 1; if(num <= 0) { num = 0; el.fadeOut('fast', function(){ el.hide(); // jQuery 1.4.3存在的bug,当fadeOut元素的父元素不可视时,fadeOut不会改变元素display callback && callback(false); }); } else { callback && callback(true); } el.data('loadingCount', num); completed = true; } }, emptyCb: function () {}, wrapCb: function () { var args = [].slice.call(arguments, 0); return function (callback) { callback && callback.apply(args); }; }, toggleEmpty: function (toggle, ctx, list) { ctx = typeof ctx === 'string' ? $(ctx, this.Dom.wrap) : ctx; $('.empty', ctx).toggle(toggle && !$(list, ctx)[0]); }, staticUrl: function (url) { // TODO 可配置不同url使用不同时间戳 return this.conf.staticUrl + url + '?4d63d1f'; }, on: function (type, data, handler) { this.Dom.wrap.bind(type, data, handler); return this; }, emit: function (type, params) { this.Dom.wrap.triggerHandler(type, params) return this; }, lock: function (id, callback) { var self = this; if(self.lockers === undefined) { self.lockers = {}; } if(!id || !self.lockers[id]) { // id为null 空白字符串等表示不使用lock self.lockers[id || ''] = true; callback(null, function () { self.lockers[id || ''] = false; }); } else { callback('locked', self.emptyCb); } }, /** * 填充this.Dom,建立必要的背景iframe * 注意:此时css尚未加载,所以样式都没生效 */ getDoms: function() { var wrap = this.Dom.wrap = this.conf.wrap , tip = wrap.next() ; if(!tip.is('.csdn_notice_tip')) { tip = $('.csdn_notice_tip'); } this.Dom.tip = tip; this.Dom.btn = this.conf.btn; wrap.append(''); return this; }, resetPosition: function () { var self = this , offset = self.Dom.btn.offset() ; self.Dom.wrap.css({ left: offset.left - 212 + 'px', top: offset.top + 25 + 'px' }); self.Dom.tip.css({ left: offset.left - 72 + 'px', top: offset.top + 18 + 'px' }); }, changeToNickname: function (ctx) { var self = this; ctx = ctx || self.Dom.wrap; var users = $('.user_name', ctx).filter(function(){ return !$(this).data('nickname'); }); if(users[0]) { $.getJSON('//api.csdn.net/service/open/nick?callback=?', { users: users.map(function(){ return this.innerHTML; }).get().join() }, function(data){ // users.each(function (i) { this.innerHTML = data[i].n; $(this).data('nickname', true); }); }); } }, addEvent: function() { var self = this , unreads = -1 , hasReadedItems = false , keepUnread = false , notifications ; self.unreads = unreads; self.initPanel(); notifications = $('.notifications', self.Dom.wrap); self.Dom.btn.click(function(e, params) { self.emit('panel_showed', params); if(self.Dom.wrap.toggle().is(':visible')) { self.Dom.tip.hide(); } else { self.emit('tip_showing'); } return false; }); $(window).resize(function(e){ self.resetPosition(); }); $(document).click(function(e) { var t = e.target; try { if(!$.contains(self.Dom.wrap[0], t) && !$.contains(self.Dom.tip[0], t)) { $(document).trigger('notify-hide'); } } catch(e) { log(e); } }); $('.notice_list_con .notice_content', self.Dom.wrap).bind('click', function (e) { var target = e.target , item = $(target).parents(".list") , index = item.index() , detail = $('.detail_con .notice_content > *:eq(' + index + ')', self.Dom.wrap) ; item.hasClass("unread")&&self.setReaded([{containIds:item.attr("data-ids").split(",")}],function(data){ keepUnread = true; item.removeClass('unread'); //去除已读id var _strReadedIds = item.attr("data-ids"); var _unread = [],_item={}; for(var i=0;i *:eq(' + index + ')', self.Dom.wrap); if(item.hasClass("action")&&target.tagName=="A"){ self.doaction({ id:$(item).attr("data-ids").split(",")[0]*1, dataApi:$(".callback",item).attr("data-api"), args:$(target).attr("data-api") },function(err, data){ $(".callback",item).html(data.msg); $(".callback",list).html(data.msg); }); } }); //当trigger click时,会将事件源对象变成这个close节点,扰乱了其它js的判断逻辑。 function hidecb(){ self.Dom.wrap.hide(); self.emit('tip_showing'); } $(document).bind("notify-hide",function(){ hidecb(); }); $('.csdn_note .close1', self.Dom.wrap).click(function () { hidecb(); }); $('.go_back', self.Dom.wrap).click(function () { self.goSlide(notifications.eq(1), notifications.eq(0), 'left'); self.emit('panel_showed'); }); $('.read_all', self.Dom.wrap).click(function () { self.setAllReaded(); return false; }); $('.prvnote, .nextnote', self.Dom.wrap).click(function () { var el = $(this); if(el.hasClass('disabled')) return; var form = $('.detail_con .notice_content .curr', self.Dom.wrap) , to = form[el.hasClass('prvnote') ? 'prev' : 'next']() , index = to.index() ; if (~index) { $('.notice_list_con .notice_content > *:eq(' + index + ')', self.Dom.wrap).removeClass('unread'); $([form[0], to[0]]).toggleClass('curr'); self.goSlide(form, to, el.hasClass('prvnote') ? 'left' : 'right').emit('detail_showed', [to, index]); } }); self.on('panel_showed', function (e, showDetail) { self.resetPosition(); if (!hasReadedItems) { $('.notice_content', self.Dom.wrap).empty(); self.getAllReaded(self.showListCbWrap(function (err, data, loading) { hasReadedItems = true; })); } if(showDetail&&showDetail.data){ self.fillList("prepend",showDetail); self.slideReset(); hasGetData = true; hasNewMsg = false; } // 显示面板内容 else if (localUreadData.length > 0&&hasNewMsg) { hasNewMsg = false; self.getUnreads(self.showListCbWrap(function (err, data, loading) { localUreadData = data.data; hasNewMsg = false; self.emit('tip_showing'); })); } if (hasGetData) { self.Dom.wrap.one('list_showed', function (e, err) { if (err) { self.error(err); } else { if(showDetail) { var unreadsItem = $('.notice_list_con .unread', self.Dom.wrap); if(unreadsItem.length === 1) { unreadsItem.trigger('click'); } } } }); } }).on('detail_showed', function (e, detail, index) { // 显示通知详情 $('.detail_con .prvnote', self.Dom.wrap).toggleClass('disabled', !(index > 0)); $('.detail_con .nextnote', self.Dom.wrap).toggleClass('disabled', !detail.next()[0]); if (!detail.data('loaded') && !$('dd', detail)[0] && !$('.empty:visible', detail)[0] && !$('.loading:visible', detail)[0]) { self.getDetail(detail); } }).on('tip_showing', function () { keepUnread = true; // if ($('.notice_list_con', self.Dom.wrap).css('display') !== 'none') { // $('.notice_list_con .notice_content .unread', self.Dom.wrap).removeClass('unread'); // } self.initBtn(); if (localUreadData.length > 0) { self.resetPosition(); $('strong', self.Dom.tip.show()).html(localUreadData.length); $('.icon-hasnotes',self.Dom.btn).show(); //派发给toolbar }else{ $('.icon-hasnotes',self.Dom.btn).hide(); } $(document).trigger("toolbar-setNotesNum",localUreadData.length); }).on('receive_unreads', function (e, data) { data.initUnreadIds&&(localUreadData = data.initUnreadIds); // 收到未读消息实时通知 typeof data === number123123 //data.realtimeMsg&&localUreadData = data.realtimeMsg; //self.unreads = unreads = (unreads === -1 ? 0 : unreads) + data; if (self.Dom.wrap.is(':visible')) { if($('.notice_list_con', self.Dom.wrap).is(':visible')){ if(data.realtimeMsg){ self.emit('panel_showed',{ data:data.data }); }else{ self.emit('panel_showed'); } } } else { self.emit('tip_showing'); } }).on('receive_setreaded', function (e, data) { var _len = localUreadData.length; // 收到设置为已读实时通知 typeof data === array or number if (keepUnread) { } else { // TODO 如果焦点在当前浏览器窗口,什么都不做 // 非查看窗口收到已读通知时需要重置状态,以便再次打开时能正确显示通知 self.unreads = _len; hasReadedItems = false; } if (_len <= 0) { self.Dom.tip.hide(); $(".icon-hasnotes",self.Dom.btn).hide(); } $('strong', self.Dom.tip).html(_len); }); $('.close2', self.Dom.tip).click(function () { self.Dom.tip.hide(); self.setReaded([], function(){ }); }); $('.tip_text', self.Dom.tip).click(function () { self.Dom.btn.trigger('click' // , ['Show one and only unread detail'] // 点击未读消息提示框后,如果未读条目只有一条,则自动进入哪一条未读 ); }); return self; }, initBtn: function(){ if(this.conf.btn.find(".icon-hasnotes").length<=0){ this.conf.btn.html(''); } }, initPanel: function () { $('.box', this.Dom.wrap).append('\
\ \
\
暂没有新通知
\
\
\ \
'); }, fillList: function(insert, data) { if(!data || !data.data || !data.data.length) return; data = data.data; var self = this , wrap = self.Dom.wrap , list = new Array(data.length) , details = new Array(data.length) ; $.each(data, function (i, v) { var action = v.isaction?" action ":""; var isslide = !v.isslide?" noslide ":""; var dataIds=(function(){ var _ids = []; for(var i=0,len=v.containIds.length,item=v.containIds;i\
\ \ ' + v.title + '\ ' + v.time + '\
\ '; var remain = v.containIds.length - self.conf.subCount; details[i]='\
\
\
\ \ ' + self.ubbDecode(v.longTitle) + '\ \
\
\
\
暂没有新通知
\ 查看其它 0 条\
'; }); $('.notice_list_con .notice_content', wrap)[insert](list.join('')); $('.detail_con .notice_content', wrap)[insert](details.join('')); self.changeToNickname(); }, fillDetail: function (detail, data) { if(!data || !data.data || !data.data.length) return; var bodyTpl = data.bodyTpl , self = this , dl = $('dl', detail) , html ; data = data.data; if (data[0].body) { html = $.map(data, function (v) { return self.feTemplate(bodyTpl).render({ userlink:self.conf.space + v.from_user, from_user:v.from_user, body:self.ubbDecode(v.body), time:v.time }); }).join(''); if (html) { dl.append(html); var remain = dl.attr('data-ids').split(',').length - data.length , url = data[0].url ; if(remain > 0 && url) { $('.notifications_more', detail).html(function (i, v) { return v.replace(/\d+/g, remain); }).attr('href', url).addClass('block'); } } } if (!html) { $('dt .count_down', detail).html(data[0].time); detail.data('loaded', true); } self.changeToNickname(dl); }, /** * 显示列表的回调包装。和getUnreads,getAllReaded配合使用,包含一些通用的操作,以及触发必要的事件 * @param {Function} callback 当正常获取到数据时的回调 * @return {Function} 包装之后的回调函数 */ showListCbWrap: function (callback) { var self = this; return function (err, data, loading) { if (err) { self.emit('list_showed', [err]); } else { callback && callback(err, data, loading); if (!loading) { var list = $('.notice_list_con .notice_content > .list', self.Dom.wrap); // 调整可见消息数量 if (list.filter(':visible').length === 0) { var n = list.filter('.unread').length; if(n < self.conf.count) { n = self.conf.count; } list.slice(n).remove(); $('.detail_con .notice_content > *', self.Dom.wrap).slice(n).remove(); } list.show(); self.slideReset(); self.emit('list_showed'); } } }; }, error: function (msg) { var self = this, func = arguments.callee; if(func.init === undefined) { func.ele = $('.error', self.Dom.wrap); self.on('panel_showed detail_showed', function () { func.ele.hide(); }); func.init = true; } msg = friendlyErrors[msg] !== undefined ? friendlyErrors[msg] : msg; func.ele.toggle(!!msg).html(msg); }, invokeAPI: function (url, params, opts, callback) { var self = this , opts = opts || {} , callback = callback || self.emptyCb ; self.lock(opts.lock === undefined || opts.lock ? url : null, function (err, unlock) { if(err) { callback(err); return; } var done = opts.loading === undefined || opts.loading ? self.loading(opts.container) : self.wrapCb(false) , data , completed = false , complete = function (xhr, status) { if(completed) return; done(function (loading) { if(status && status !== 'success') { callback(status, null, loading); } else { if(data.status !== 200) { callback(data.error || data.status, data, loading); } else { if(opts.list) { // /detail/i.test(url) && (data.data = []); // DEV self.toggleEmpty(!loading && data.data && !data.data.length, opts.container, opts.list); } callback(null, data, loading); } } unlock(); completed = true; }); } ; setTimeout(function () { complete(null, 'timeout'); }, 20000); $.ajax({ url: self.conf.api + url, data: params, dataType: 'jsonp', // TODO jsonp方式调用不能产生正确的timeout错误等,考虑换成支持跨域的xhr(在ff chrome ie8+) success: function (json) { if(completed) return; data = json; }, complete: complete }); }); }, getUnreads: function (callback) { var self = this; self.invokeAPI('/get_unread?jsonpcallback=?', {}, { container: '.notice_list_con', list: '.notice_content > .list' }, function (err, data, loading) { self.fillList('prepend', data); callback && callback(err, data, loading); }); }, doaction : function(data,callback){ var self = this; self.invokeAPI('/do_action?jsonpcallback=?', { id:data.id, dataApi:data.dataApi+"?me="+currUser.username+'&'+data.args, }, { }, function (err, data, loading) { callback && callback(err, data, loading); }); }, getAllReaded: function (callback) { var self = this; self.invokeAPI('/get_all?jsonpcallback=?', { username: currUser.username, status: 1, count: self.conf.count || 5, subcount: self.conf.subcount || 5 }, { container: '.notice_list_con', list: '.notice_content > .list' }, function (err, data, loading) { self.fillList('append', data); callback && callback(err, data, loading); }); }, setAllReaded: function(){ if(!localUreadData.length){ return; } this.setReaded([],function(){ $(".csdn_note .unread").each(function(i){ $(this).removeClass("unread"); localUreadData=[]; }); }); }, setReaded: function (data, next) { var self = this; self.invokeAPI('/set_readed?jsonpcallback=?', { ids: $.map(data, function (i) { return i.containIds.join(); }).join() }, { loading: false },function(data){ next&&next(data); }); }, getlocalUnread: function(){ return localUreadData; }, isGetAll: function(){ return hasGetData; }, isHasNewMsg: function(){ return hasNewMsg; }, getDetail: function(detail, start, limit){ var self = this , ids = $('dl', detail).attr('data-ids').split(',') ; start = start || 0; limit = limit || self.conf.subCount; if (ids.length > 0) { self.invokeAPI('/get_details?jsonpcallback=?', { ids: ids.slice(start, start + limit).join() }, { container: detail, list: 'dl > dd', lock: false }, function (err, data) { if (err) { self.error(err); } else { self.fillDetail(detail, data); } }); } }, /** * 动画切换 * @param {jQuery Object} from 动画开始的元素 * @param {jQuery Object} to 动画结束的元素 * @param {String} direction to在from的左边还是右边, left right */ goSlide: function(from, to, direction) { var self = this , speed = 110 // + 3000 // DEV , offsetW = from.width() , content = to.parents('.notice_content:first') , fromComplete, toComplete ; self.emit('goSliding'); if (!to.hasClass('curr')) { from.removeClass('curr'); to.addClass('curr'); } from.css({ position: 'relative' }); to.css({ position: 'absolute' , top: 0 , left: (direction === 'left' ? -offsetW : offsetW) + 'px' , width: offsetW }).show(); content.height(function (i, v) { return v - from.height() + Math.max(from.height(), to.height()); }); fromComplete = function () { from.css('position', '').hide(); }; from.animate({ left: (direction === 'left' ? offsetW : -offsetW) + 'px' }, speed, fromComplete); toComplete = function () { to.css({ position: '' , top: '' , left: '' }); content.css('height', ''); }; to.animate({ left: 0 }, speed, toComplete); self.Dom.wrap.one('goSliding', function () { from.stop(); fromComplete.call(from[0]); to.stop(); toComplete.call(to[0]); }); return this; }, slideReset: function() { var self = this , container = $('.notice_list_con .notice_content', self.Dom.wrap) , items = container.children().filter(':visible') ; $('.notifications', this.Dom.wrap).eq(0).addClass('curr').show().end() .slice(1).hide(); ; if(items.length > self.conf.count) { // container.css({ // overflow: 'auto' // , height: '255px' // }); container.addClass("hover-overflow"); } }, /* * 【LOGIC】检查登录 */ checkLogin: function(callback) { try{ currUser.username = getCookie("UserName") || currUser.username; currUser.userInfo = getCookie("UserInfo") || currUser.userInfo; currUser.username && callback && callback(currUser.username); }catch(e){ log(e); } }, initRealtime: function () { var self = this; // 兼容独立和合并的realtime.js if(csdn.RealtimeClient === undefined) { $.ajax({ url: self.staticUrl(self.conf['realtime.js']) , dataType: 'script' , cache: true // 已通过staticUrl对外链文件提供了缓存支持,getScript()可能会始终在url结尾加时间戳 , success: arguments.callee.bind(self) }); return; } self.conf['socket.io.js'] = self.staticUrl(self.conf['socket.io.js']); self.realtimeClient = new csdn.RealtimeClient($.extend({ channel: currUser.username }, self.conf), function (msg) { // 分发收到的实时消息 if(typeof msg === 'object') { if(msg.setReaded) { self.emit('receive_setreaded', [msg.setReaded]); } if(msg.initUnreadIds&&msg.initUnreadIds.length){ hasNewMsg = true; self.emit('receive_unreads', msg); } if(msg.realtimeMsg){ hasNewMsg = true; localUreadData = localUreadData.concat(msg.data); self.emit('receive_unreads', msg); } } }); }, /* * UBB转义 */ ubbDecode : function(content){ var _this = this; content = $.trim(content); var re = /\[code=([\w#\.]+)\]([\s\S]*?)\[\/code\]/ig; function replaceQuote(str) { var m = /\[quote=([^\]]+)]([\s\S]*)\[\/quote\]/gi.exec(str); if (m) { return str.replace(m[0], '
引用“' + m[1] + '”的评论:' + replaceQuote(m[2]) + '
'); } else { return str; } } var codelist = []; while ((mc = re.exec(content)) != null) { codelist.push(mc[0]); content = content.replace(mc[0], "--code--"); } content = replaceQuote(content); content = content.replace(/\[reply]([\s\S]*?)\[\/reply\][\r\n]{0,2}/gi, "回复$1:"); content = content.replace(/\[url=([^\]]+)]([\s\S]*?)\[\/url\]/gi, '$2'); content = content.replace(/\[img(=([^\]]+))?]([\s\S]*?)\[\/img\]/gi, ''); content = content.replace(/\r?\n/ig, "
"); if (codelist.length > 0) { var re1 = /--code--/ig; var i = 0; while ((mc = re1.exec(content)) != null) { content = content.replace(mc[0], codelist[i]); i++; } } content = content.replace(/\[code=([\w#\.]+)\]([\s\S]*?)\[\/code\]/ig, function (m0, m1, m2) { if ($.trim(m2) == "") return ''; return '
' + _this.HTMLEncode(m2) + '
'; }); content = content.replace(/(|
)/ig, function (m0) { if ($.trim(m0) == "") return ''; //return _this.HTMLEncode(m0); return "  "; }); //针对转义的"做处理 content = content.replace(/(\\"e\;|\"e\;)/ig, function (m0) { if ($.trim(m0) == "") return ''; //return _this.HTMLEncode(m0); return ""; }); return content; }, HTMLEncode : function(str) { var s = ""; if(str.length == 0) return ""; s = str.replace(/&/g, "&").replace(//g, ">").replace(/\'/g, "'").replace(/\"/g, """); return s; }, /** * 简单模板替换 * @param {String} tempStr 待替换字符串 * @return {String} 替换后的html */ feTemplate : function(tempStr){ // TODO 未处理模板字段重复出现的问题 [fixed] // 未处理返回的模板对象复用的问题 [fixed] // 测试用例 //jsfiddle.net/SdzfU/2/ return { render:function(conf){ var result=tempStr; for(var name in conf){ if(conf.hasOwnProperty(name)){ result=result.replace(new RegExp("{"+"%"+name+"%"+"}","g"),conf[name]); } } return result; } } } }; })(window); (function($, window, undefined) { if ($ === undefined) { // 按需加载jQuery var done = false , callback = arguments.callee , script = document.createElement('script') , head = document.getElementsByTagName('head')[0] || document.documentElement ; script.src = '//csdnimg.cn/www/js/jquery-1.4.2.min.js'; script.charset = 'utf-8'; script.onload = script.onreadystatechange = function () { if(!done && (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete')) { done = true; try { callback(window.jQuery, window); } catch(e) { window.console && window.console.log(e); } script.onload = script.onreadystatechange = null; if(head && script.parentNode) { head.removeChild(script); } } }; head.insertBefore(script, head.firstChild); return; } // 初始化通知面板 var script = $("#noticeScript") , opts = { instance: 'csdn_note' , btnId: script.attr('btnId') || 'header_notice_num' , wrapId: 'note1' } ; opts.btn = $('#' + opts.btnId); if(!opts.btn[0]) { return; } $.map(['instance', 'wrapId' , 'realtime', 'api', 'app', 'space', 'count', 'subCount' , 'staticUrl', 'cssUrl' , 'realtime.js', 'channel', 'socket.io.js', 'socket.io options'], function (v) { opts[v] = script.attr(v.replace(/[. ]/g, '-')) || opts[v]; }); if(opts.instance === "csdn_note") { $('\ ').insertBefore(script); } $('\ ').insertBefore(script).hide(); window[opts.instance] = new csdn.note(opts); })(window.jQuery, window);